/**
 * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved.
 */

#ifndef PANDA_PLUGINS_ECMASCRIPT_RUNTIME_NATIVE_FRAME_INL_H
#define PANDA_PLUGINS_ECMASCRIPT_RUNTIME_NATIVE_FRAME_INL_H

#include "plugins/ecmascript/runtime/interpreter/js_frame.h"
#include "plugins/ecmascript/runtime/js_thread.h"
#include "plugins/ecmascript/runtime/ecma_runtime_call_info.h"
#include "plugins/ecmascript/runtime/handle_storage_check.h"
#include "runtime/interpreter/frame.h"

namespace ark::ecmascript {
/* static */
inline Frame *JSFrame::CreateNativeFrame(JSThread *jsThread, Method *method, Frame *prevFrame, uint32_t nregs,
                                         uint32_t numActualArgs)
{
    ASSERT(jsThread == JSThread::GetCurrent());

    Frame *newFrame = CreateFrame(jsThread->GetStackFrameAllocator(), nregs, method, prevFrame, nregs, numActualArgs);
    if (UNLIKELY(newFrame == nullptr)) {
        return nullptr;
    }
    LOG_IF(newFrame == nullptr, FATAL, ECMASCRIPT) << "Cannot allocate native frame";
    newFrame->SetInvoke();
    newFrame->SetDynamic();
    return newFrame;
}

/* static */
inline void JSFrame::DestroyNativeFrame(JSThread *jsThread, Frame *frame)
{
    ASSERT(jsThread == JSThread::GetCurrent());
    DestroyFrame(jsThread->GetStackFrameAllocator(), frame);
}

/* static */
inline void JSFrame::InitNativeFrameArgs(Frame *frame, uint32_t numArgs, const JSTaggedValue *args)
{
    uint32_t numActualArgs = frame->GetNumActualArgs();
    ASSERT(numArgs <= numActualArgs);

    for (uint32_t i = 0; i < numArgs; ++i) {
        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
        frame->GetVReg(i).SetValue(args[i].GetRawData());
    }
    for (uint32_t i = numArgs; i < numActualArgs; ++i) {
        frame->GetVReg(i).SetValue(JSTaggedValue::VALUE_UNDEFINED);
    }
    frame->SetInvoke();
}

/* static */
inline JSTaggedValue JSFrame::ExecuteNativeMethod(JSThread *jsThread, Frame *frame, Method *method,
                                                  uint32_t numActualArgs)
{
    ASSERT(jsThread == JSThread::GetCurrent());
    if (UNLIKELY((!jsThread->StackOverflowCheck<true, true>()))) {
        return JSTaggedValue::Exception();
    }
    [[maybe_unused]] HandleStorageCheck handleStorageCheck(jsThread);
    EcmaRuntimeCallInfo callInfo(jsThread, numActualArgs, reinterpret_cast<JSTaggedValue *>(&frame->GetVReg(0)));
    auto ecmaEntryPoint = reinterpret_cast<EcmaEntrypoint>(method->GetNativePointer());
    JSTaggedValue retValue = ecmaEntryPoint(&callInfo);

    return retValue;
}
}  // namespace ark::ecmascript

#endif  // PANDA_PLUGINS_ECMASCRIPT_RUNTIME_NATIVE_FRAME_INL_H
